#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QMouseEvent>
#include <QString>
#include <QStyle>
#include <QThread>
#include <QtDebug>
#include <iostream>
#include <windows.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::SnakeWindow) {
  ui->setupUi(this);
  // setWindowIcon(QIcon(":/image/image/logo.ico"));

  this->setWindowTitle("贪吃蛇");

  //设置窗体大小
  this->resize((x_max + 7) * label_size, (y_max + 2) * label_size + 10);

  mLabel = new QLabel(this);
  mLabel->setStyleSheet("font-size:20px;");
  mLabel->setGeometry(x_max * label_size, 9 * label_size, 6 * label_size,
                      4 * label_size);
  mLabel->setAlignment(Qt::AlignCenter);
  //注：函数setAlignment()能消除布局中的空隙，让两个控件紧紧挨在一起
  mLabel->setText("分数:" + QString::number(score, 10) + '\n' +
                  "关数:" + QString::number(level, 10) + '\n' + "步数：" +
                  QString::number(steps, 10));
  mLabel->show();

  init();

  QToolBar *toolbar = this->addToolBar("toolbar");
  toolbar->addAction(ui->actionbegin);
  toolbar->addAction(ui->actionstop);
  toolbar->addAction(ui->actionresume_2);
  toolbar->addAction(ui->actionsave);
  toolbar->addAction(ui->actionload);
  toolbar->addAction(ui->actionexit);
  toolbar->addAction(ui->actionrestart);
  toolbar->setMovable(false);

  connect(ui->buttons->buttons()[0], SIGNAL(clicked()), ui->actionbegin,
          SIGNAL(triggered()));
  connect(ui->buttons->buttons()[1], SIGNAL(clicked()), ui->actionstop,
          SIGNAL(triggered()));
  connect(ui->buttons->buttons()[2], SIGNAL(clicked()), ui->actionresume_2,
          SIGNAL(triggered()));
  connect(ui->buttons->buttons()[3], SIGNAL(clicked()), ui->actionsave,
          SIGNAL(triggered()));
  connect(ui->buttons->buttons()[4], SIGNAL(clicked()), ui->actionload,
          SIGNAL(triggered()));
  connect(ui->buttons->buttons()[5], SIGNAL(clicked()), ui->actionexit,
          SIGNAL(triggered()));
  connect(ui->buttons->buttons()[6], SIGNAL(clicked()), ui->actionrestart,
          SIGNAL(triggered()));
  connect(&timer, SIGNAL(timeout()), this, SLOT(snakeMoveSlots()));
  connect(ui->actionexit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
  connect(ui->actionbegin, SIGNAL(triggered()), this, SLOT(startGameSlots()));
  connect(ui->actionstop, SIGNAL(triggered()), this, SLOT(pauseGameSlots()));
  connect(ui->actionresume_2, SIGNAL(triggered()), this,
          SLOT(resumeGameSlots()));
  connect(ui->actionload, SIGNAL(triggered()), this, SLOT(loadGameSlots()));
  connect(ui->actionsave, SIGNAL(triggered()), this, SLOT(saveGameSlots()));
  connect(ui->actionrestart, SIGNAL(triggered()), this,
          SLOT(restartGameSlots()));
}

MainWindow::~MainWindow() {
  delete ui;

  for (int i = 0; i < x_max; i++)
    for (int j = 0; j < y_max; j++)
      delete squares[i][j].label;

  delete mLabel;
}

// 画出显示分数区域的边界
void MainWindow::drawViewArea() {
  for (int x = x_max; x < x_max + 7; x++)
    for (int y = 0; y < y_max; y += y_max - 1) {
      QLabel *label = new QLabel(this);
      label->setStyleSheet("background:gray");
      label->setGeometry(x * label_size, (y + 2) * label_size + 10,
                         label_size - 1, label_size - 1);
      label->show();
    }

  for (int y = 1; y < y_max - 1; y++) {
    QLabel *label = new QLabel(this);
    label->setStyleSheet("background:gray");
    label->setGeometry((x_max + 6) * label_size, (y + 2) * label_size + 10,
                       label_size - 1, label_size - 1);
    label->show();
  }
}

// 初始化游戏
void MainWindow::init() {
  movable = false;
  started = false;
  putable = true;
  foodCount = 0;
  foodTotal = 0;
  moveSpeed = 400;
  steps = 0;
  score = 0;
  level = 1;
  dScore = 1;
  dX = 1;
  dY = 0;

  ui->actionbegin->setEnabled(true);
  ui->actionsave->setEnabled(false);
  ui->actionexit->setEnabled(true);
  ui->actionload->setEnabled(true);
  ui->actionresume_2->setEnabled(false);
  ui->actionstop->setEnabled(false);
  ui->actionrestart->setEnabled(false);

  ui->buttons->buttons()[0]->show();
  ui->buttons->buttons()[3]->hide();
  ui->buttons->buttons()[5]->show();
  ui->buttons->buttons()[4]->show();
  ui->buttons->buttons()[2]->hide();
  ui->buttons->buttons()[1]->hide();
  ui->buttons->buttons()[6]->hide();

  initSquares();

  drawBorder();
  if (flag_for_drawViewArea) {
    drawViewArea();
    flag_for_drawViewArea = false;
  }

  initSnake();
}

void MainWindow::setBlocks(int x, int y) {
  if (!putable)
    return;
  if (x == 0 || x == x_max - 1 || y == 0 || y == y_max - 1)
    return;

  Square &item = squares[x][y];

  if (item.is_food)
    return;

  if (item.is_border) {
    item.is_border = false;
    item.can_use = true;
    item.label->setStyleSheet("background-color:rgba(0,0,0,0.2)");
  } else if (item.can_use) {
    item.is_border = true;
    item.can_use = false;
    item.label->setStyleSheet("background:gray");
  }
  item.label->show();
}

// 这个函数的作用是把所有的label都初始化为未遮挡
void MainWindow::initSquares() {
  for (int x = 0; x < x_max; x++)
    for (int y = 0; y < y_max; y++) {
      MyQLabel *label = squares[x][y].label;
      if (label == nullptr) {
        label = (squares[x][y].label = new MyQLabel(this));
        connect(label, SIGNAL(mousePress(int, int)), this,
                SLOT(setBlocks(int, int)));
        label->p = &squares[x][y];
      }
      label->setStyleSheet("background-color:rgba(0,0,0,0.2)");
      label->setGeometry(x * label_size, (y + 2) * label_size + 10,
                         label_size - 1, label_size - 1);
      label->show();

      squares[x][y].x = x;
      squares[x][y].y = y;
      squares[x][y].can_use = true;
      squares[x][y].is_food = false;
    }
}

void MainWindow::initSnake() {
  snake.erase();
  snake.append(SnakeSquare(5, 6));
  snake.append(SnakeSquare(6, 6));
  for (auto square : snake) {
    Square &a = squares[square.shuju.x][square.shuju.y];
    a.can_use = false;
    a.is_food = false;
    a.is_border = false;
    a.label->setStyleSheet("background-color:#6ea8c9");
    a.label->show();
  }
}

// 画边界
void MainWindow::drawBorder() {
  for (int x = 0; x < x_max; x++)
    for (int y = 0; y < y_max; y++)
      if (x == 0 || y == 0 || x == x_max - 1 || y == y_max - 1) {
        squares[x][y].label->setStyleSheet("background:gray");
        squares[x][y].label->show();
        squares[x][y].can_use = false;
      }
}

// 移动操作
void MainWindow::moveSnake() {
  SnakeSquare &head = snake[-1];
  Square &tempNode = squares[head.x + dX][head.y + dY];
  if (!tempNode.can_use) {
    gameOver();
    return;
  }
  if (tempNode.is_food) {
    foodLeft += dFood;
    foodCount--;
    foodTotal++;
    score += dScore;
    tempNode.is_food = false;
  }
  SnakeSquare new_head(head.x + dX, head.y + dY);
  snake.append(std::move(new_head));
  // tempNode->label->setStyleSheet("QLabel{border-image:
  // url(:/image/image/tail.png);}");
  tempNode.label->setStyleSheet("background-color:#6ea8c9");
  tempNode.label->show();
  if (foodLeft) {
    foodLeft--;
  } else {
    squares[snake[0].x][snake[0].y].can_use = true;
    squares[snake[0].x][snake[0].y].label->setStyleSheet(
        "background-color:rgba(0,0,0,0.2)");
    squares[snake[0].x][snake[0].y].label->show();
    snake.erase(0, 1);
  }
  tempNode.can_use = false;
  // qDebug() << snake.length();
  createFood();

  steps++;

  showViewArea();
}

// 游戏结束
void MainWindow::gameOver() {
  timer.stop();

  QMessageBox::information(this, "Message:", "Game is over!", QMessageBox::Ok);

  movable = false;
  started = false;
  putable = false;

  ui->actionbegin->setEnabled(false);
  ui->actionsave->setEnabled(false);
  ui->actionexit->setEnabled(true);
  ui->actionload->setEnabled(false);
  ui->actionresume_2->setEnabled(false);
  ui->actionstop->setEnabled(false);
  ui->actionrestart->setEnabled(true);

  ui->buttons->buttons()[0]->hide();
  ui->buttons->buttons()[3]->hide();
  ui->buttons->buttons()[5]->show();
  ui->buttons->buttons()[4]->hide();
  ui->buttons->buttons()[2]->hide();
  ui->buttons->buttons()[1]->hide();
  ui->buttons->buttons()[6]->show();
}

// 显示分数和等级
void MainWindow::showViewArea() {
  level = (foodTotal / 10) + 1;
  // 等级最高为8级，等级越高移动越快，吃东西的分也越多
  if (level >= 8)
    level = 8;

  dScore = level;

  moveSpeed = 50 * (9 - level); // 计算移动速度

  // qDebug() << moveSpeed;

  viewText = QString::number(score, 10);
  mLabel->setText("分数:" + viewText + '\n' +
                  "关数:" + QString::number(level, 10) + '\n' + "步数：" +
                  QString::number(steps, 10));
  mLabel->setAlignment(Qt::AlignCenter);
  mLabel->show();
}

void MainWindow::snakeMoveSlots() { moveSnake(); }
void MainWindow::pauseGameSlots() { stop(); }
void MainWindow::resumeGameSlots() { resume(); }

void MainWindow::restartGameSlots() { init(); }

void MainWindow::startGameSlots() {
  if (started)
    return;

  createFood();
  movable = true;
  started = true;
  putable = false;
  moveSnake();

  showViewArea();

  // 开始移动
  timer.start(moveSpeed);

  ui->actionbegin->setEnabled(false);
  ui->actionsave->setEnabled(false);
  ui->actionexit->setEnabled(true);
  ui->actionload->setEnabled(false);
  ui->actionresume_2->setEnabled(false);
  ui->actionstop->setEnabled(true);
  ui->actionrestart->setEnabled(false);

  ui->buttons->buttons()[0]->hide();
  ui->buttons->buttons()[3]->hide();
  ui->buttons->buttons()[5]->show();
  ui->buttons->buttons()[4]->hide();
  ui->buttons->buttons()[2]->hide();
  ui->buttons->buttons()[1]->show();
  ui->buttons->buttons()[6]->hide();
}

void MainWindow::loadGameSlots() {
  if (started)
    return;

  QFileDialog loader(this);
  loader.setWindowTitle("加载保存的游戏文档");
  loader.setDirectory("."); // 这个函数可以设置默认的文件夹路径
  loader.setNameFilter("*.tchsh"); // 文件扩展名为tchsh（即贪吃蛇）
  loader.setFileMode(QFileDialog::ExistingFile); // 设置成只能选一个存在的文件

  if (!loader.exec())
    return;

  QString file = loader.selectedFiles()[0];
  char *file_url = file.toUtf8().data();

  if (!strlen(file_url))
    return;

  FILE *opened = fopen(file_url, "r");

  // 一些单个参量的读取
  fscanf(opened, "%d %d %d %d %d %d %d %d %d %d", &dX, &dY, &foodCount,
         &foodTotal, &moveSpeed, &level, &score, &dScore, &foodLeft, &steps);
  showViewArea();

  // 背景的读取
  initSquares();
  int x, y;
  while (fscanf(opened, "%d %d", &x, &y)) {
    // 用不可能出现的值作为结尾，所以需要存文件的时候以-1 -1标志结尾
    if (x == -1)
      break;

    fscanf(opened, "%d %d", &squares[x][y].can_use, &squares[x][y].is_food);
    // 约定只存不能走及有食物的格子，所以就不检查can_use了
    if (squares[x][y].is_food) {
      squares[x][y].label->setStyleSheet("background-color:#fed46e");
    } else
      squares[x][y].label->setStyleSheet("background:gray");
    squares[x][y].label->show();
  }
  drawBorder();

  // 读取蛇的位置
  snake.erase();
  while (fscanf(opened, "%d %d", &x, &y) != EOF) {
    snake.append(SnakeSquare(x, y));
  }
  fclose(opened);
  for (auto square : snake) {
    Square &a = squares[square.shuju.x][square.shuju.y];
    a.can_use = false;
    a.is_border = false;
    a.is_food = false;
    a.label->setStyleSheet("background-color:#6ea8c9");
    a.label->show();
  }

  movable = false;
  started = true;
  putable = false;
  showViewArea();

  ui->actionbegin->setEnabled(false);
  ui->actionsave->setEnabled(true);
  ui->actionexit->setEnabled(true);
  ui->actionload->setEnabled(false);
  ui->actionresume_2->setEnabled(true);
  ui->actionstop->setEnabled(false);
  ui->actionrestart->setEnabled(true);

  ui->buttons->buttons()[0]->hide();
  ui->buttons->buttons()[3]->show();
  ui->buttons->buttons()[5]->show();
  ui->buttons->buttons()[4]->hide();
  ui->buttons->buttons()[2]->show();
  ui->buttons->buttons()[1]->hide();
  ui->buttons->buttons()[6]->show();
}

void MainWindow::saveGameSlots() {
  if (!started)
    return;

  // 这个函数会自动调用一个对话框让用户选择保存的文件名和地址等
  char *file_url =
      QFileDialog::getSaveFileName(this, "选择保存位置", ".", "*.tchsh")
          .toUtf8()
          .data();

  // 这个判断是因为如果用户点了取消上面那个函数就会返回空串，继续执行下去就会抛出异常闪退
  if (!strlen(file_url))
    return;

  FILE *file = fopen(file_url, "w");

  // 一些单一变量
  fprintf(file, "%d %d %d %d %d %d %d %d %d %d\n", dX, dY, foodCount, foodTotal,
          moveSpeed, level, score, dScore, foodLeft, steps);

  // 背景的障碍物和食物信息
  for (int i = 1; i < x_max - 1; i++)
    for (int j = 1; j < y_max - 1; j++)
      if (squares[i][j].is_food || !squares[i][j].can_use)
        fprintf(file, "%d %d %d %d\n", i, j, squares[i][j].can_use,
                squares[i][j].is_food);
  // 以-1 -1提醒读取时的结束
  fprintf(file, "-1 -1\n");

  // 蛇的位置信息
  for (auto square : snake) {
    SnakeSquare &item = square.shuju;
    fprintf(file, "%d %d\n", item.x, item.y);
  }

  fclose(file);
}

// 反方向不做任何操作，同方向加速（直接进行moveSnake()）
void MainWindow::keyPressEvent(QKeyEvent *e) {
  // 空格是暂停和继续的快捷键
  if (e->key() == Qt::Key_Space && started) {
    if (timer.isActive())
      stop();
    else
      resume();
  }

  if (!movable)
    return;

  switch (e->key()) {
  case Qt::Key_Left:
    if (dX != 1) {
      dX = -1;
      dY = 0;
      moveSnake();
    }
    break;
  case Qt::Key_Right:
    if (dX != -1) {
      dX = 1;
      dY = 0;
      moveSnake();
    }
    break;
  case Qt::Key_Up:
    if (dY != 1) {
      dX = 0;
      dY = -1;
      moveSnake();
    }
    break;
  case Qt::Key_Down:
    if (dY != -1) {
      dX = 0;
      dY = 1;
      moveSnake();
    }
    break;
  default:
    return;
  }
}

void MainWindow::stop() {
  movable = false;
  timer.stop();

  ui->actionbegin->setEnabled(false);
  ui->actionsave->setEnabled(true);
  ui->actionexit->setEnabled(true);
  ui->actionload->setEnabled(false);
  ui->actionresume_2->setEnabled(true);
  ui->actionstop->setEnabled(false);
  ui->actionrestart->setEnabled(true);

  ui->buttons->buttons()[0]->hide();
  ui->buttons->buttons()[3]->show();
  ui->buttons->buttons()[5]->show();
  ui->buttons->buttons()[4]->hide();
  ui->buttons->buttons()[2]->show();
  ui->buttons->buttons()[1]->hide();
  ui->buttons->buttons()[6]->show();
}

void MainWindow::resume() {
  if (!started)
    return;

  movable = true;
  timer.start(moveSpeed);

  ui->actionbegin->setEnabled(false);
  ui->actionsave->setEnabled(false);
  ui->actionexit->setEnabled(true);
  ui->actionload->setEnabled(false);
  ui->actionresume_2->setEnabled(false);
  ui->actionstop->setEnabled(true);
  ui->actionrestart->setEnabled(false);

  ui->buttons->buttons()[0]->hide();
  ui->buttons->buttons()[3]->hide();
  ui->buttons->buttons()[5]->show();
  ui->buttons->buttons()[4]->hide();
  ui->buttons->buttons()[2]->hide();
  ui->buttons->buttons()[1]->show();
  ui->buttons->buttons()[6]->hide();
}

void MainWindow::createFood() {
  // 本来想支持多食物的，不想写了
  if (foodCount)
    return;

  // 随机生成食物坐标，为了在后期不至于重复在不可用位置生成食物，先统计空格的个数
  int space_usable = 0;
  for (int i = 0; i < x_max; ++i)
    for (int j = 0; j < y_max; ++j)
      space_usable += squares[i][j].can_use;

  if (!space_usable) {
    gameOver();
    return;
  }

  //确定最终的食物生成位置
  int foodX;
  int foodY;
  srand((unsigned)time(0));
  int location = rand() % space_usable;
  for (int i = 0; i < x_max; i++)
    for (int j = 0; j < y_max; j++)
      if (squares[i][j].can_use)
        if (!(location--)) {
          foodX = i;
          foodY = j;
          i = x_max;
          j = y_max;
        }

  squares[foodX][foodY].is_food = true;
  squares[foodX][foodY].label->setStyleSheet("background-color:#fed46e");
  squares[foodX][foodY].label->show();

  foodCount++;

  // 这是网上找的添加图片背景的代码，暂时用不上
  // QPixmap pixmap("/image/image/food.png");
  // squares[foodX][foodY]->label->setStyleSheet("background:lightblue");
  // squares[foodX][foodY]->label->setStyleSheet("QLabel{border-image:
  // url(:/image/image/food.png);}");
  // squares[foodX][foodY]->label->setPixmap(pixmap);
}
